using System;
using System.Threading;
using Budgeteer.Services.Common;
using Xunit;

namespace Test.UnitTests.Budgeteer.Services
{
    public class TimeFacts
    {
        private readonly long ticksInOneSecond;

        public TimeFacts()
        {
            DateTime time1 = DateTime.Now;
            DateTime time2 = DateTime.Now.AddMilliseconds(1000);
            ticksInOneSecond = time2.Ticks - time1.Ticks;
        }

        [Fact]
        public void UnfrozenTimeShouldReportTheSameTimesAsDateTime()
        {
            Assert.True(ticksInOneSecond > DateTime.Now.Ticks - Time.Now.Ticks);
        }

        [Fact]
        public void UnfrozenTimeTimesShouldAdvanceAsNormal()
        {
            DateTime time1 = Time.Now;
            Thread.Sleep(100);
            Assert.True(Time.Now.CompareTo(time1) > 0);
        }

        [Fact]
        public void FrozenTimeShouldKeepReportingTheSameTime()
        {
            Time.Freeze();
            DateTime time1 = Time.Now;
            Thread.Sleep(100);
            DateTime time2 = Time.Now;
            Assert.Equal(time2, time1);
            Time.Unfreeze();
        }

        [Fact]
        public void FreezingTimeWhenAlreadyFrozenDoesNotChangeFreezeTime()
        {
            Time.Freeze();
            DateTime expected = Time.Now;
            Thread.Sleep(50);
            Time.Freeze();
            DateTime actual = Time.Now;
            Assert.Equal(expected,actual);
            Time.Unfreeze();
        }

        [Fact]
        public void UnfreezingTimeReportsSystemTimeAgain()
        {
            Time.Freeze();
            Thread.Sleep(50);
            Assert.False(DateTime.Now == Time.Now);
            Time.Unfreeze();
            Assert.Equal(DateTime.Now,Time.Now);
        }

        [Fact]
        public void FreezingTimeShouldSetMillisecondsToZero()
        {
            Time.Freeze();
            Assert.Equal(0,Time.Now.Millisecond);
            Time.Unfreeze();
        }

        [Fact]
        public void FreezingTimeShouldSetTicksToARoundNumber()
        {
            Time.Freeze();
            long ticks = Time.Now.Ticks;
            Assert.Equal(0,ticks % 100000);
            Time.Unfreeze();
        }

        [Fact]
        public void FreezingTimeShouldReportSetTime()
        {
            DateTime expected = new DateTime(2004, 9, 3);
            Time.Freeze(expected);
            Assert.Equal(expected, Time.Now);
            Time.Unfreeze();
            Assert.Equal(DateTime.Now,Time.Now);
        }

        [Fact]
        public void TimeShouldUnfreezeOnDisposeCall()
        {
            DateTime expected = new DateTime(2004,9,3);
            using(Time.Freeze(expected))
            {
                Assert.Equal(expected,Time.Now);
            }
            Assert.Equal(DateTime.Now,Time.Now);
        }
    }
}